<template>
  <a-card>
    <a-button-group style="margin-bottom: 10px">
      <a-button size="small" type="primary" icon="vertical-align-bottom" @click="autoToBottom" />
      <a-button size="small" type="danger" icon="delete" @click="cleanLog" />
    </a-button-group>

    <!-- @keyup.delete="cleanLog"
      @keyup.esc="disconnect"
      @keyup.enter="connection" -->

    <div ref="logContainer" tabindex="-1" @scroll="scrollEvent" style="height: 450px; overflow-y: scroll; background: #333; color: #aaa; padding: 10px">
      <div style="color: #18d035; font-size: 14px" v-for="(log, index) of logList" :key="index">
        <span style="color: #dcdcdc"> {{ log.timestamp }} </span>

        <span style="color: #90ad2b" v-if="log.level == 'INFO'"> {{ log.level }} </span>
        <span style="color: #a8c023" v-if="log.level == 'DEBUG'"> {{ log.level }} </span>
        <span style="color: #fffa1c" v-if="log.level == 'WARN'"> {{ log.level }} </span>
        <span style="color: #e3270e" v-if="log.level == 'ERROR'"> {{ log.level }} </span>
        ---
        <span style="color: #dcdcdc"> [{{ log.threadName }}] </span>
        <span style="color: #229379"> {{ log.className }} </span>
        <span style="color: #dcdcdc"> : {{ log.body }} </span>
        <div style="color: #e3270e; white-space: pre-wrap" v-if="log.exception">{{ log.exception }}</div>
        <div style="color: #dcdcdc; white-space: pre-wrap" v-if="log.cause">{{ log.cause }}</div>
      </div>
    </div>
  </a-card>
</template>

<script>
// 安装并引入相关模块
import SockJS from 'sockjs-client'
import Stomp from 'stompjs'
import { mapGetters } from 'vuex'

function throttle(fn, interval = 300) {
  let timer = null
  return function () {
    let context = this
    let args = arguments
    if (!timer) {
      timer = setTimeout(function () {
        fn.apply(context, args)
        timer = null
      }, interval)
    }
  }
}

function debounce(fn, delay) {
  // 维护一个 timer，用来记录当前执行函数状态
  let timer = null
  return function () {
    // 通过 ‘this’ 和 ‘arguments’ 获取函数的作用域和变量
    let context = this
    let args = arguments
    // 清理掉正在执行的函数，并重新执行
    clearTimeout(timer)
    timer = setTimeout(function () {
      fn.apply(context, args)
    }, delay)
  }
}

export default {
  name: 'logger',
  components: {},
  data() {
    return {
      stompClient: null,
      timer: null,
      logList: [],
      isScrollBottom: true,
      scrollTop: 0
      //   desc: `    step1:  选中 console div \r\n
      // step2:  Esc___暂停;   Enter___继续;   Del___清空`
    }
  },
  created: function () {
    this.initWebSocket()
  },
  mounted: function () {
    this.scrollToBottom()
  },
  beforeDestroy: function () {
    this.disconnect()
  },
  computed: {
    ...mapGetters(['userName', 'userToken'])
  },
  watch: {
    $route: function () {
      if (this.isScrollBottom) {
        this.scrollToBottom()
      } else {
        this.scrollToBottom(this.scrollTop)
      }
    }
  },
  methods: {
    initWebSocket() {
      this.connection()
      // 断开重连机制,尝试发送消息,捕获异常发生时重连
      //   let self = this
      //   this.timer = setInterval(() => {
      //     try {
      //       self.stompClient.send('test')
      //     } catch (err) {
      //       console.log('断线了: ' + err)
      //       self.connection()
      //     }
      //   }, 5000)
    },
    connection() {
      this.disconnect()
      const socket = new SockJS(process.env.VUE_APP_API_BASE_URL + '/ws')
      // 获取STOMP子协议的客户端对象
      this.stompClient = Stomp.over(socket)
      // 定义客户端的认证信息,按需求配置
      var headers = {
        username: this.userName,
        'client-id': this.userToken
        // additional header
      }
      // 向服务器发起websocket连接
      this.stompClient.connect(
        headers,
        (frame) => {
          this.stompClient.subscribe('/sub/log', (msg) => {
            if (this.logList.length > 500) {
              this.logList = this.logList.slice(1)
            }
            let loggerMsg = JSON.parse(msg.body)
            this.logList.push(loggerMsg)
            if (this.isScrollBottom) {
              this.scrollToBottom()
            }
          })
        },
        (err) => {
          // 连接发生错误时的处理函数
          console.log(err)
        }
      )
      window.addEventListener('logger:close', this.disconnect)
    },
    // 断开连接
    disconnect() {
      if (this.stompClient != null) {
        this.stompClient.disconnect()
        console.log('Disconnected')
        // clearInterval(this.timer)
        window.removeEventListener('logger:close', this.disconnect)
      }
    },
    cleanLog() {
      this.isScrollBottom = true
      this.logList = []
    },
    autoToBottom() {
      if (!this.isScrollBottom) {
        this.isScrollBottom = true
      }
      this.scrollToBottom()
    },
    scrollToBottom(scrollTop) {
      const div = this.$refs.logContainer
      this.$nextTick(() => {
        div.scrollTop = scrollTop || div.scrollHeight
      })
    },
    scrollEvent: throttle(function () {
      const div = this.$refs.logContainer
      this.scrollTop = div.scrollTop
      const offsetHeight = div.offsetHeight
      const scrollTop = div.scrollTop
      const scrollHeight = div.scrollHeight
      if (scrollHeight - offsetHeight - scrollTop <= 20) {
        this.isScrollBottom = true
      } else {
        this.isScrollBottom = false
      }
    }, 500)
  }
}
</script>
<style scoped>
.body {
  word-break: normal;
  width: auto;
  display: block;
  white-space: pre;
  word-wrap: break-word;
  overflow: hidden;
}
</style>
